﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Design;
using System.Windows.Forms.Design;
using System.Diagnostics;
using System.Windows.Forms;
using UIDesigner.SurfaceProperties;
using System.Reflection;
using System.Drawing;
using SharedClasses;
using UIDesigner.Designers.Controls;
using System.Threading;
using UIDesigner.Designers.Forms;

namespace UIDesigner.Editors
{
    public class SurfaceActionEditor : UITypeEditor 
    {
        private const int WM_TEST_VISIBILITY = ((int) WindowsAPI.WindowsMessage.WM_USER) + 76516; 
        private bool m_bControlsAdded = false;
        private ctrlLinkBuildLabel m_ctrlLink;
        private Rectangle m_rcBounds;
        private Control m_ctrlGridView;
        private bool m_bIsSubclassing;
        private static WindowsAPI.WindowProc m_fnNewWindowProc;
        private static int m_fnOldWindowProc;
        private static int m_hGridView;
        private static List<SurfaceActionEditor> m_rgEditors;
        private SurfaceActionType m_objSurfaceActionType;
        private PropertyGrid m_ctrlGrid;
        private AccessibleObject m_objAccessible;

        ~SurfaceActionEditor()
        {
            if (m_bIsSubclassing)
            {
                WindowsAPI.SetWindowLong(m_hGridView, WindowsAPI.WindowLongIndex.GWL_WNDPROC, m_fnOldWindowProc);
                SubclassTracker.RemoveProc(m_fnNewWindowProc);
            }
        }

        public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
        {
            return UITypeEditorEditStyle.Modal;
        }

        public override bool GetPaintValueSupported(System.ComponentModel.ITypeDescriptorContext context)
        {
            return true;
        }

        public ctrlLinkBuildLabel LinkBuildLabel
        {
            get 
            { 
                return m_ctrlLink; 
            }
        }

        public Rectangle Bounds
        {
            get 
            { 
                return m_rcBounds; 
            }
        }

        public void RemoveLinks()
        {
            if (m_rgEditors != null)
            {
                Monitor.Enter(m_fnNewWindowProc);

                foreach (SurfaceActionEditor objEditor in m_rgEditors)
                {
                    if (objEditor != this)
                    {
                        m_ctrlGridView.Controls.Remove(objEditor.LinkBuildLabel);
                        objEditor.LinkBuildLabel.Dispose();
                    }
                }

                m_rgEditors.Clear();

                Monitor.Exit(m_fnNewWindowProc);
            }

            if (m_ctrlLink != null)
            {
                m_ctrlGridView.Controls.Remove(m_ctrlLink);
                m_ctrlLink.Dispose();
                m_bControlsAdded = false;
            }
        }

        public override void PaintValue(PaintValueEventArgs e)
        {
            object objGridEntry = e.Context;
            Type objType = objGridEntry.GetType();
            PropertyInfo objProperty = objType.GetProperty("AccessibilityObject");
            AccessibleObject objAccessible = (AccessibleObject)objProperty.GetValue(objGridEntry, null);
            Rectangle rcBounds = objAccessible.Bounds;

            m_objSurfaceActionType = (SurfaceActionType)e.Value;

            m_ctrlGridView = m_objSurfaceActionType.PropertyGridView;
            m_hGridView = m_ctrlGridView.Handle.ToInt32();

            m_rcBounds = m_ctrlGridView.RectangleToClient(rcBounds);

            if (!m_bControlsAdded)
            {
                m_ctrlLink = new ctrlLinkBuildLabel();

                m_ctrlGrid = (PropertyGrid)((IServiceProvider)m_objSurfaceActionType.Host).GetService(typeof(PropertyGrid));

                if (m_objSurfaceActionType.ActionCategory == SurfaceActionCategory.ApplySavedProperty)
                {
                    m_ctrlLink.Text = "Apply";
                    m_ctrlLink.HasBuildButton = true;

                    if (SavedSurfaceProperties.AppySelectedText == "(None Selected)")
                    {
                        m_ctrlLink.LinkEnabled = false;
                    }
                    else
                    {
                        m_ctrlLink.LinkEnabled = true;
                    }
                }
                else if (m_objSurfaceActionType.ActionCategory == SurfaceActionCategory.RemoveSurfaceControls)
                {
                    m_ctrlLink.Text = "Remove";
                }

                m_ctrlLink.BackColor = m_ctrlGridView.BackColor;
                m_ctrlLink.LinkClicked += new EventHandler(LinkClicked);
                m_ctrlLink.Build += new EventHandler(Build); 

                m_ctrlGridView.Controls.Add(m_ctrlLink);

                m_bControlsAdded = true;

                if (m_fnNewWindowProc == null)
                {
                    m_fnNewWindowProc = WindowProc;

                    m_fnOldWindowProc = WindowsAPI.SetWindowLong(m_hGridView, WindowsAPI.WindowLongIndex.GWL_WNDPROC, m_fnNewWindowProc);
                    SubclassTracker.AddProc(m_hGridView, m_fnNewWindowProc, m_fnOldWindowProc);

                    m_rgEditors = new List<SurfaceActionEditor>();

                    m_bIsSubclassing = true;
                }

                Monitor.Enter(m_fnNewWindowProc);
                m_rgEditors.Add(this);
                Monitor.Exit(m_fnNewWindowProc);

                m_objAccessible = objAccessible;
            }

            m_objSurfaceActionType.Editor = this;

            m_ctrlLink.Visible = true;
            m_ctrlLink.Height = m_rcBounds.Height;
            m_ctrlLink.Location = new Point(m_rcBounds.Right - m_ctrlLink.Width, m_rcBounds.Top);

            base.PaintValue(e);
        }

        public void TestVisibility()
        {
            Rectangle rcBounds = m_objAccessible.Bounds;

            rcBounds = m_ctrlGridView.RectangleToClient(rcBounds);

            if (rcBounds.Width == 0 || rcBounds.Height == 0)
            {
                m_ctrlLink.Visible = false; 
            }
        }

        private static int WindowProc(int hWnd, int uMsg, int wParam, int lParam)
        {
            if (uMsg == (int)WindowsAPI.WindowsMessage.WM_LBUTTONDOWN || uMsg == (int)WindowsAPI.WindowsMessage.WM_LBUTTONUP)
            {
                short x = 0;
                short y = 0;
                Point pt;
                bool bReturn = false;

                BitShift.GetHighLowWord(lParam, ref x, ref y);

                pt = new Point(x, y);

                Monitor.Enter(m_fnNewWindowProc);

                foreach (SurfaceActionEditor objEditor in m_rgEditors)
                {
                    if (objEditor.Bounds.Contains(pt))
                    {
                        bReturn = true;
                    }
                }

                WindowsAPI.PostMessage(hWnd, WM_TEST_VISIBILITY, 0, 0);

                Monitor.Exit(m_fnNewWindowProc);

                if (bReturn)
                {
                    return 0;
                }
            }
            else if (uMsg == (int)WindowsAPI.WindowsMessage.WM_KEYDOWN || uMsg == (int)WindowsAPI.WindowsMessage.WM_KEYUP)
            {
                WindowsAPI.PostMessage(hWnd, WM_TEST_VISIBILITY, 0, 0);
            }
            else if (uMsg == WM_TEST_VISIBILITY)
            {
                foreach (SurfaceActionEditor objEditor in m_rgEditors)
                {
                    objEditor.TestVisibility();
                }
            }

            return WindowsAPI.CallWindowProc(m_fnOldWindowProc, hWnd, uMsg, wParam, lParam);
        }

        private void Build(object sender, EventArgs e)
        {
            if (m_objSurfaceActionType.ActionCategory == SurfaceActionCategory.ApplySavedProperty)
            {
                SurfacePropertiesBase objProperties = m_objSurfaceActionType.SurfaceProperties;
                frmSurfaceProperties frmProperties = new frmSurfaceProperties(m_objSurfaceActionType, objProperties);

                if (frmProperties.ShowDialog() == DialogResult.OK)
                {
                    SavedSurfaceProperties.SelectedProperties = frmProperties.SelectedProperties; 

                    m_bControlsAdded = false;
                    this.RemoveLinks();

                    m_ctrlGrid.Invalidate();
                    m_ctrlGrid.SelectedObject = m_ctrlGrid.SelectedObject;
                    m_ctrlGrid.Refresh();
                }
            }
            else
            {
                Debugger.Break();
            }
        }

        private void LinkClicked(object sender, EventArgs e)
        {
            if (m_objSurfaceActionType.ActionCategory == SurfaceActionCategory.ApplySavedProperty)
            {
                SurfacePropertiesBase objSelected = SavedSurfaceProperties.SelectedProperties;

                m_objSurfaceActionType.BaseObjectControl.ApplySurfaceProperties(objSelected);
            }
            else if (m_objSurfaceActionType.ActionCategory == SurfaceActionCategory.RemoveSurfaceControls)
            {
                m_objSurfaceActionType.BaseObjectControl.RemoveSurfaceControls();
            }
            else
            {
                Debugger.Break();
            }
        }

        public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
            SurfaceActionType objSurfaceActionType = (SurfaceActionType)value;

            return null;
        }
    }
}
